-> CargoResult<ops::TargetConfig> {
let key = format!("target.{}", triple);
- let ar = try!(config.get_string(&format!("{}.ar", key)));
- let linker = try!(config.get_string(&format!("{}.linker", key)));
-
let mut ret = ops::TargetConfig {
- ar: ar.map(|p| p.0),
- linker: linker.map(|p| p.0),
+ ar: try!(config.get_path(&format!("{}.ar", key))),
+ linker: try!(config.get_path(&format!("{}.linker", key))),
overrides: HashMap::new(),
};
let table = match try!(config.get_table(&key)) {
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::collections::{HashSet, HashMap};
+use std::path::{Path, PathBuf};
use std::str;
use std::sync::Arc;
-use std::path::PathBuf;
use regex::Regex;
}
/// Get the user-specified linker for a particular host or target
- pub fn linker(&self, kind: Kind) -> Option<&str> {
- self.target_config(kind).linker.as_ref().map(|s| &s[..])
+ pub fn linker(&self, kind: Kind) -> Option<&Path> {
+ self.target_config(kind).linker.as_ref().map(|s| s.as_ref())
}
/// Get the user-specified `ar` program for a particular host or target
- pub fn ar(&self, kind: Kind) -> Option<&str> {
- self.target_config(kind).ar.as_ref().map(|s| &s[..])
+ pub fn ar(&self, kind: Kind) -> Option<&Path> {
+ self.target_config(kind).ar.as_ref().map(|s| s.as_ref())
}
/// Get the target configuration for a particular host or target
use std::collections::{HashSet, HashMap};
use std::env;
-use std::ffi::OsString;
+use std::ffi::{OsStr, OsString};
use std::fs;
use std::io::prelude::*;
use std::path::{self, Path, PathBuf};
#[derive(Clone, Default)]
pub struct TargetConfig {
- pub ar: Option<String>,
- pub linker: Option<String>,
+ pub ar: Option<PathBuf>,
+ pub linker: Option<PathBuf>,
pub overrides: HashMap<String, BuildOutput>,
}
fn build_plugin_args(cmd: &mut CommandPrototype, cx: &Context, pkg: &Package,
target: &Target, kind: Kind) {
fn opt(cmd: &mut CommandPrototype, key: &str, prefix: &str,
- val: Option<&str>) {
+ val: Option<&OsStr>) {
if let Some(val) = val {
- cmd.arg(key).arg(&format!("{}{}", prefix, val));
+ let mut joined = OsString::from(prefix);
+ joined.push(val);
+ cmd.arg(key).arg(joined);
}
}
cmd.arg("--emit=dep-info,link");
if kind == Kind::Target {
- opt(cmd, "--target", "", cx.requested_target());
+ opt(cmd, "--target", "", cx.requested_target().map(|s| s.as_ref()));
}
- opt(cmd, "-C", "ar=", cx.ar(kind));
- opt(cmd, "-C", "linker=", cx.linker(kind));
+ opt(cmd, "-C", "ar=", cx.ar(kind).map(|s| s.as_ref()));
+ opt(cmd, "-C", "linker=", cx.linker(kind).map(|s| s.as_ref()));
}
fn build_deps_args(cmd: &mut CommandPrototype,
}
}
+ pub fn get_path(&self, key: &str) -> CargoResult<Option<PathBuf>> {
+ if let Some((specified_path, path_to_config)) = try!(self.get_string(&key)) {
+ if specified_path.contains("/") || (cfg!(windows) && specified_path.contains("\\")) {
+ // An absolute or a relative path
+ let prefix_path = path_to_config.parent().unwrap().parent().unwrap();
+ // Joining an absolute path to any path results in the given absolute path
+ Ok(Some(prefix_path.join(specified_path)))
+ } else {
+ // A pathless name
+ Ok(Some(PathBuf::from(specified_path)))
+ }
+ } else {
+ Ok(None)
+ }
+ }
+
pub fn get_list(&self, key: &str) -> CargoResult<Option<(Vec<(String, PathBuf)>, PathBuf)>> {
match try!(self.get(key)) {
Some(CV::List(i, path)) => Ok(Some((i, path))),
fn get_tool(&self, tool: &str) -> CargoResult<PathBuf> {
let var = format!("build.{}", tool);
- if let Some((tool, path)) = try!(self.get_string(&var)) {
- // If this tool has a path separator in it, calculate the path
- // relative to the config file (specified by `path`). To do that we
- // chop off the `.cargo/config` at the end of the path and then join
- // on the tool.
- if tool.contains("/") || (cfg!(windows) && tool.contains("\\")) {
- let path = path.parent().unwrap().parent().unwrap();
- return Ok(path.join(tool))
- }
- return Ok(PathBuf::from(tool))
+ if let Some(tool_path) = try!(self.get_path(&var)) {
+ return Ok(tool_path);
}
let var = tool.chars().flat_map(|c| c.to_uppercase()).collect::<String>();
All of the following keys are optional, and their defaults are listed as their
value unless otherwise noted.
+Key values that specify a tool may be given as an absolute path, a relative path
+or as a pathless tool name. Absolute paths and pathless tool names are used as
+given. Relative paths are resolved relative to the parent directory of the
+`.cargo` directory of the config file that the value resides within.
+
```toml
# An array of paths to local repositories which are to be used as overrides for
# dependencies. For more information see the Cargo Guide.
# literal string "$triple", and it will apply whenever that target triple is
# being compiled to.
[target]
-# For cargo builds which do not mention --target, these are the ar/linker which
-# are passed to rustc to use (via `-C ar=` and `-C linker=`). By default these
-# flags are not passed to the compiler.
+# For cargo builds which do not mention --target, these are the ar/linker tools
+# which are passed to rustc to use (via `-C ar=` and `-C linker=`). By default
+# these flags are not passed to the compiler.
ar = ".."
linker = ".."
[target.$triple]
-# Similar to the above ar/linker configuration, but this only applies to when
-# the `$triple` is being compiled for.
+# Similar to the above ar/linker tool configuration, but this only applies to
+# when the `$triple` is being compiled for.
ar = ".."
linker = ".."
[build]
jobs = 1 # number of jobs to run by default (default to # cpus)
-rustc = "rustc" # path to the compiler to execute
-rustdoc = "rustdoc" # path to the doc generator to execute
+rustc = "rustc" # the rust compiler tool
+rustdoc = "rustdoc" # the doc generator tool
target-dir = "target" # path of where to place all generated artifacts
```
`rustdoc` instance instead.
* `CARGO_TARGET_DIR` - Location of where to place all generated artifacts,
relative to the current working directory.
+
+Settings specified via config files take precedence over those specified via environment variables.
--- /dev/null
+use support::{path2url, project, execs};
+use support::{COMPILING, RUNNING};
+use hamcrest::assert_that;
+
+fn setup() {
+}
+
+test!(pathless_tools {
+ let target = ::rustc_host();
+
+ let foo = project("foo")
+ .file("Cargo.toml", r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ authors = []
+
+ [lib]
+ name = "foo"
+ "#)
+ .file("src/lib.rs", "")
+ .file(".cargo/config", &format!(r#"
+ [target.{}]
+ ar = "nonexistent-ar"
+ linker = "nonexistent-linker"
+ "#, target));
+
+ assert_that(foo.cargo_process("build").arg("--verbose"),
+ execs().with_stdout(&format!("\
+{compiling} foo v0.0.1 ({url})
+{running} `rustc [..] -C ar=nonexistent-ar -C linker=nonexistent-linker [..]`
+", compiling = COMPILING, running = RUNNING, url = foo.url())))
+});
+
+test!(absolute_tools {
+ let target = ::rustc_host();
+
+ // Escaped as they appear within a TOML config file
+ let config = if cfg!(windows) {
+ (r#"C:\\bogus\\nonexistent-ar"#, r#"C:\\bogus\\nonexistent-linker"#)
+ } else {
+ (r#"/bogus/nonexistent-ar"#, r#"/bogus/nonexistent-linker"#)
+ };
+
+ let foo = project("foo")
+ .file("Cargo.toml", r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ authors = []
+
+ [lib]
+ name = "foo"
+ "#)
+ .file("src/lib.rs", "")
+ .file(".cargo/config", &format!(r#"
+ [target.{target}]
+ ar = "{ar}"
+ linker = "{linker}"
+ "#, target = target, ar = config.0, linker = config.1));
+
+ let output = if cfg!(windows) {
+ (r#"C:\bogus\nonexistent-ar"#, r#"C:\bogus\nonexistent-linker"#)
+ } else {
+ (r#"/bogus/nonexistent-ar"#, r#"/bogus/nonexistent-linker"#)
+ };
+
+ assert_that(foo.cargo_process("build").arg("--verbose"),
+ execs().with_stdout(&format!("\
+{compiling} foo v0.0.1 ({url})
+{running} `rustc [..] -C ar={ar} -C linker={linker} [..]`
+", compiling = COMPILING, running = RUNNING, url = foo.url(), ar = output.0, linker = output.1)))
+});
+
+test!(relative_tools {
+ let target = ::rustc_host();
+
+ // Escaped as they appear within a TOML config file
+ let config = if cfg!(windows) {
+ (r#".\\nonexistent-ar"#, r#".\\tools\\nonexistent-linker"#)
+ } else {
+ (r#"./nonexistent-ar"#, r#"./tools/nonexistent-linker"#)
+ };
+
+ // Funky directory structure to test that relative tool paths are made absolute
+ // by reference to the `.cargo/..` directory and not to (for example) the CWD.
+ let origin = project("origin")
+ .file("foo/Cargo.toml", r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ authors = []
+
+ [lib]
+ name = "foo"
+ "#)
+ .file("foo/src/lib.rs", "")
+ .file(".cargo/config", &format!(r#"
+ [target.{target}]
+ ar = "{ar}"
+ linker = "{linker}"
+ "#, target = target, ar = config.0, linker = config.1));
+
+ let foo_path = origin.root().join("foo");
+ let foo_url = path2url(foo_path.clone());
+ let prefix = origin.root().into_os_string().into_string().unwrap();
+ let output = if cfg!(windows) {
+ (format!(r#"{}\.\nonexistent-ar"#, prefix),
+ format!(r#"{}\.\tools\nonexistent-linker"#, prefix))
+ } else {
+ (format!(r#"{}/./nonexistent-ar"#, prefix),
+ format!(r#"{}/./tools/nonexistent-linker"#, prefix))
+ };
+
+ assert_that(origin.cargo_process("build").cwd(foo_path).arg("--verbose"),
+ execs().with_stdout(&format!("\
+{compiling} foo v0.0.1 ({url})
+{running} `rustc [..] -C ar={ar} -C linker={linker} [..]`
+", compiling = COMPILING, running = RUNNING, url = foo_url, ar = output.0, linker = output.1)))
+});
mod test_cargo_rustc;
mod test_cargo_search;
mod test_cargo_test;
+mod test_cargo_tool_paths;
mod test_cargo_version;
mod test_shell;